package com.example.anliku.service.serviceImpl;

import com.alibaba.fastjson.JSON;
import com.example.anliku.Utils.RedisUtil;
import com.example.anliku.entity.*;
import com.example.anliku.mapper.ExampleClazzMapper;
import com.example.anliku.mapper.ExampleKnowledgeMapper;
import com.example.anliku.mapper.ExampleMapper;
import com.example.anliku.service.ElasticSearchService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.System;
import java.util.*;

/**
 * @author ClayeLink
 * @date 2021/2/22 14:00
 */
@Service
@Slf4j
public class ElasticSearchServiceImpl implements ElasticSearchService {

    private final String INDEX_EXAMPLE = "anliku_example";

    @Resource
    private RestHighLevelClient restHighLevelClient;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ExampleMapper exampleMapper;

    @Resource
    private ExampleKnowledgeMapper exampleKnowledgeMapper;

    @Resource
    private ExampleClazzMapper exampleClazzMapper;

    @Override
    public Boolean insert(ExampleForES exampleForES) {
        IndexRequest request = new IndexRequest(INDEX_EXAMPLE);
        request.id(exampleForES.getExampleId().toString());
        request.timeout(TimeValue.timeValueSeconds(10));
        request.source(JSON.toJSONString(exampleForES), XContentType.JSON);
        IndexResponse index = null;
        try {
            index = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> 增加方法出现异常 ");
        }
        if ("CREATED".equals(index.status().toString()) && index != null) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean delete(Integer id) {
        DeleteRequest request = new DeleteRequest(INDEX_EXAMPLE, id.toString());
        DeleteResponse delete = null;
        try {
            delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> 删除方法出现异常 ");
        }
        if ("OK".equals(delete.status().toString()) && delete != null) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean upadte(ExampleForES exampleForES) {
        UpdateRequest request = new UpdateRequest(INDEX_EXAMPLE, exampleForES.getExampleId().toString());
        request.doc(JSON.toJSONString(exampleForES), XContentType.JSON);
        UpdateResponse update = null;
        try {
            update = restHighLevelClient.update(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> 修改方法出现异常 ");
        }
        if ("OK".equals(update.status().toString()) && update != null) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public ESForSort select(Integer page, Integer size, String keyword, Integer dec) {
        SearchRequest request = new SearchRequest(INDEX_EXAMPLE);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(page - 1);
        sourceBuilder.size(size);
        if (dec == 0) {
            sourceBuilder.sort("exampleStartTime", SortOrder.DESC);
        } else if (dec == 1) {
            sourceBuilder.sort("exampleDownload", SortOrder.DESC);
        }
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.multiMatchQuery(keyword, "exampleName", "exampleTypeName", "exampleKnowledgeId", "exampleClazz", "exampleIntroduction", "exampleUserName"))
                .filter(QueryBuilders.termQuery("exampleState", 1))
                .filter(QueryBuilders.termQuery("examplePublicState", 1));
        sourceBuilder.query(boolQuery);
        request.source(sourceBuilder);
        SearchResponse search = null;
        try {
            search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> 查询方法出现异常 ");
        }
        if(search==null){
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> search NullPointerException出现异常 ");
            return null;
        }

        if ("OK".equals(search.status().toString()) && search != null) {
            HashMap[] list = new HashMap[search.getHits().getHits().length];
            for (int i = 0; i < search.getHits().getHits().length; i++) {
                SearchHit hit = search.getHits().getHits()[i];
                HashMap<String, Object> hashMap = (HashMap<String, Object>) hit.getSourceAsMap();
                List<ExampleKnowledge> knowledges = JSON.parseArray((String) hashMap.get("exampleKnowledgeId"), ExampleKnowledge.class);
                List<ExampleClazz> clazzes = JSON.parseArray((String) hashMap.get("exampleClazz"), ExampleClazz.class);
                hashMap.put("exampleKnowledgeId", knowledges);
                hashMap.put("exampleClazz", clazzes);
                hashMap.put("exampleComment", redisUtil.get("comment" + hashMap.get("exampleId")));
                list[i] = hashMap;
            }
            Long totalSize = Long.valueOf(0);
            totalSize = search.getHits().getTotalHits().value;
            return new ESForSort(totalSize, list);
        } else {
            return null;
        }

    }

    @Override
    public ExampleForES selectById(Integer id) {
        GetRequest request = new GetRequest(INDEX_EXAMPLE, id.toString());
        GetResponse documentFields = null;
        try {
            documentFields = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> 根据ID查询方法出现异常 ");
        }
        if (documentFields.isExists()) {
            Map map = documentFields.getSourceAsMap();
            ExampleForES exampleForES = new ExampleForES();
            exampleForES.setExampleId((Integer) map.get("exampleId"));
            exampleForES.setExampleName((String) map.get("exampleName"));
            exampleForES.setExampleStartTime(new Date((Long) map.get("exampleStartTime")));
            exampleForES.setExampleState((Integer) map.get("exampleState"));
            exampleForES.setExampleTypeName((String) map.get("exampleTypeName"));
            exampleForES.setExampleKnowledgeId((String) map.get("exampleKnowledgeId"));
            exampleForES.setExampleClazz((String) map.get("exampleClazz"));
            exampleForES.setExampleImage((String) map.get("exampleImage"));
            exampleForES.setExampleIntroduction((String) map.get("exampleIntroduction"));
            exampleForES.setExampleUserName((String) map.get("exampleUserName"));
            exampleForES.setExamplePublicState((Integer) map.get("examplePublicState"));
            return exampleForES;
        } else {
            return null;
        }

    }

    @Override
    public Boolean updateAll(Integer exampleId) {
        boolean es = delete(exampleId);
        if (es) {
            Example example = exampleMapper.selectByPrimaryKey(exampleId);
            ExampleForES exampleForES = new ExampleForES();
            exampleForES.setExampleId(example.getExampleId());
            exampleForES.setExampleName(example.getExampleName());
            exampleForES.setExampleStartTime(example.getExampleStartTime());
            exampleForES.setExampleState(example.getExampleState());
            exampleForES.setExampleTypeName(example.getExampleTypeName());
            exampleForES.setExampleKnowledgeId(JSON.toJSONString(exampleKnowledgeMapper.selectAllByExampleKnowledgeExampleId(example.getExampleId())));
            exampleForES.setExampleClazz(JSON.toJSONString(exampleClazzMapper.selectAllByExampleClazzExampleId(example.getExampleId())));
            exampleForES.setExampleImage(example.getExampleImage());
            exampleForES.setExampleIntroduction(example.getExampleIntroduction());
            exampleForES.setExampleUserName(example.getExampleUserName());
            exampleForES.setExamplePublicState(example.getExamplePublicState());
            exampleForES.setExampleDownload(0);
            boolean es1 = insert(exampleForES);
            if (es1) {
                return true;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    @Override
    public Boolean blukDelete(List<String> list) {
        BulkRequest bulkRequest = new BulkRequest(INDEX_EXAMPLE);

        for (String i : list) {
            bulkRequest.add(new DeleteRequest(INDEX_EXAMPLE, i));
        }

        BulkResponse bulk = null;
        try {
            bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> 批量删除出现异常 ");
        }
        if ("OK".equals(bulk.status().toString()) && bulk != null) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public void allDelete() {
        DeleteByQueryRequest delete = new DeleteByQueryRequest(INDEX_EXAMPLE);
        delete.setQuery(QueryBuilders.matchAllQuery());
        try {
            BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.deleteByQuery(delete, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> 删除索引下所有数据出现异常 ");
        }
    }

    @Override
    public Boolean blukUpadteForRedis() {
        BulkRequest bulkRequest = new BulkRequest(INDEX_EXAMPLE);
        List<Example> examples = exampleMapper.selectAll();
        for (int i = 0; i < examples.size(); i++) {
            System.out.println(examples.get(i).getExampleId());
            Integer download = (Integer) redisUtil.get("download" + examples.get(i).getExampleId());
            ExampleForES exampleForES = selectById(examples.get(i).getExampleId());
            exampleForES.setExampleDownload(download);
            bulkRequest.add(new UpdateRequest(INDEX_EXAMPLE, examples.get(i).getExampleId().toString()).doc(JSON.toJSONString(exampleForES), XContentType.JSON));
        }
        BulkResponse bulk = null;
        try {
            bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("ElasticSearch: ElasticSearchServiceImpl ---> 批量更新redis出现异常 ");
        }
        if ("OK".equals(bulk.status().toString()) && bulk != null) {
            return true;
        } else {
            return false;
        }
    }
}
